/**
 * 网格列表类，用于存储行列关系的数据
 * 支持不固定列数的行，内部使用二维数组存储
 */
export class GridList<T> {
    private _data: T[][] = [];

    /**
     * 构造函数
     * @param rowsOrData 初始行数或二维数组数据
     */
    constructor(rowsOrData: number | T[][] = 0) {
        if (Array.isArray(rowsOrData)) {
            // 如果传入的是二维数组，直接使用
            this.setData(rowsOrData);
        } else {
            // 否则按行数初始化
            this.resize(rowsOrData);
        }
    }

    /**
     * 重新设置行数
     * @param rows 行数
     */
    resize(rows: number): void {
        // 保留现有数据
        const oldData = [...this._data];

        // 创建新数组
        this._data = new Array(rows);

        // 复制旧数据
        for (let i = 0; i < Math.min(rows, oldData.length); i++) {
            this._data[i] = [...oldData[i] || []];
        }

        // 初始化新行
        for (let i = oldData.length; i < rows; i++) {
            this._data[i] = [];
        }
    }

    /**
     * 获取行数
     */
    get rows(): number {
        return this._data.length;
    }

    /**
     * 获取指定行的列数
     * @param row 行索引
     */
    getColsInRow(row: number): number {
        if (row < 0 || row >= this._data.length) {
            throw new Error(`行索引越界: ${row}`);
        }
        return this._data[row].length;
    }

    /**
     * 检查坐标是否有效
     * @param row 行索引
     * @param col 列索引
     */
    isValidCoord(row: number, col: number): boolean {
        return row >= 0 && row < this._data.length &&
            col >= 0 && col < this._data[row].length;
    }

    /**
     * 通过行列坐标获取元素
     * @param row 行索引
     * @param col 列索引
     */
    get(row: number, col: number): T {
        if (!this.isValidCoord(row, col)) {
            throw new Error(`坐标越界: (${row}, ${col})`);
        }
        return this._data[row][col];
    }

    /**
     * 通过行列坐标设置元素
     * @param row 行索引
     * @param col 列索引
     * @param value 要设置的值
     */
    set(row: number, col: number, value: T): void {
        // 确保行存在
        while (row >= this._data.length) {
            this._data.push([]);
        }

        // 设置值，如果列超出范围会自动扩展
        this._data[row][col] = value;
    }

    /**
     * 在指定行添加一个元素
     * @param row 行索引
     * @param value 要添加的值
     */
    addToRow(row: number, value: T): void {
        // 确保行存在
        while (row >= this._data.length) {
            this._data.push([]);
        }

        this._data[row].push(value);
    }

    /**
     * 添加一行
     * @param values 行数据
     */
    addRow(values: T[] = []): number {
        this._data.push([...values]);
        return this._data.length - 1; // 返回新行的索引
    }

    /**
     * 获取指定行的所有元素
     * @param row 行索引
     */
    getRow(row: number): T[] {
        if (row < 0 || row >= this._data.length) {
            throw new Error(`行索引越界: ${row}`);
        }
        return [...this._data[row]];
    }

    /**
     * 获取指定列的所有元素
     * @param col 列索引
     * @returns 包含该列所有元素的数组，如果某行不存在该列，对应位置为undefined
     */
    getCol(col: number): (T | undefined)[] {
        const result: (T | undefined)[] = [];
        for (let row = 0; row < this._data.length; row++) {
            result.push(row < this._data.length && col < this._data[row].length ?
                this._data[row][col] : undefined);
        }
        return result;
    }

    /**
     * 交换两个位置的元素
     * @param row1 第一个位置的行
     * @param col1 第一个位置的列
     * @param row2 第二个位置的行
     * @param col2 第二个位置的列
     * @returns 交换是否成功
     */
    swap(row1: number, col1: number, row2: number, col2: number): boolean {
        // 检查两个位置是否都有效
        if (!this.isValidCoord(row1, col1) || !this.isValidCoord(row2, col2)) {
            return false;
        }

        // 交换元素
        const temp = this._data[row1][col1];
        this._data[row1][col1] = this._data[row2][col2];
        this._data[row2][col2] = temp;

        return true;
    }

    /**
     * 遍历所有元素
     * @param callback 回调函数，参数为(值, 行, 列)
     */
    forEach(callback: (value: T, row: number, col: number) => void): void {
        for (let row = 0; row < this._data.length; row++) {
            for (let col = 0; col < this._data[row].length; col++) {
                callback(this._data[row][col], row, col);
            }
        }
    }

    /**
     * 将所有元素展平为一维数组
     */
    flatten(): T[] {
        return this._data.reduce((acc, row) => acc.concat(row), []);
    }

    /**
     * 查找元素的位置
     * @param predicate 判断函数
     * @returns 找到的第一个元素的位置 [row, col]，未找到则返回 [-1, -1]
     */
    findPosition(predicate: (value: T, row: number, col: number) => boolean): [number, number] {
        for (let row = 0; row < this._data.length; row++) {
            for (let col = 0; col < this._data[row].length; col++) {
                if (predicate(this._data[row][col], row, col)) {
                    return [row, col];
                }
            }
        }
        return [-1, -1];
    }

    /**
     * 从指定行列位置移除元素
     * @param row 行索引
     * @param col 列索引
     * @returns 被移除的元素，如果位置无效则返回undefined
     */
    removeAt(row: number, col: number): T | undefined {
        if (!this.isValidCoord(row, col)) {
            return undefined;
        }

        const removed = this._data[row][col];
        this._data[row].splice(col, 1);
        return removed;
    }

    /**
     * 标记删除元素（不改变索引）
     * @param row 行索引
     * @param col 列索引
     * @param marker 删除标记值
     * @returns 被标记的元素，如果位置无效则返回undefined
     */
    markAsRemoved(row: number, col: number, marker: T): T | undefined {
        if (!this.isValidCoord(row, col)) {
            return undefined;
        }

        const original = this._data[row][col];
        this._data[row][col] = marker;
        return original;
    }

    /**
     * 清空列表
     */
    clear(): void {
        this._data = [];
    }

    /**
     * 设置整个二维数组数据
     * @param data 二维数组数据
     */
    setData(data: T[][]): void {
        if (!Array.isArray(data)) {
            throw new Error('输入必须是二维数组');
        }
        // 深拷贝数据以避免引用问题
        this._data = data.map(row => [...row]);
    }

    /**
     * 获取原始二维数组数据（深拷贝）
     * @returns 二维数组数据的副本
     */
    getData(): T[][] {
        return this._data.map(row => [...row]);
    }

    /**
     * 将网格数据序列化为JSON字符串
     * @returns JSON字符串
     */
    toJSON(): string {
        return JSON.stringify(this._data);
    }

    /**
     * 从JSON字符串反序列化网格数据
     * @param json JSON字符串
     * @returns 是否成功加载
     */
    fromJSON(json: string): boolean {
        try {
            const data = JSON.parse(json);
            if (Array.isArray(data)) {
                this._data = data;
                return true;
            }
            return false;
        } catch (error) {
            console.error("解析JSON失败:", error);
            return false;
        }
    }
}